package cn.xej.easyexcel.service.impl;

import cn.xej.easyexcel.common.BaseQuery;
import cn.xej.easyexcel.common.RespObj;
import cn.xej.easyexcel.export.IExportService;
import cn.xej.easyexcel.mapper.DataExportMapper;
import cn.xej.easyexcel.pojo.DataExport;
import cn.xej.easyexcel.service.ExportService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author <a href="mailto:enjie.xu@yunhutech.com">xiaoming</a>
 * @since 2021/6/8
 * 实现ApplicationContextAware接口后，当这个类被spring加载后，就能够在这个类中获取到spring的上下文操作符ApplicationContext，
 * 通过ApplicationContext就能够轻松的获取所有Spring管理的bean
 *
 * 实现InitializingBean接口，为bean提供了初始化方法的方式，它只包括afterPropertiesSet方法，凡是继承该接口的类，在初始化bean的时候都会执行该方法
 */
@Service
public class ExportServiceImpl implements ExportService, ApplicationContextAware, InitializingBean {

    private Map<String, IExportService> BEAN_MAP;
    private  ApplicationContext applicationContext;
    //创建使用固定线程数的线程池
    private static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(5);



    @Resource
    private DataExportMapper dataExportMapper;
    /**
     * 生成excel
     * 上传excel
     * @param exportBean
     * @return
     */
    @Override
    public RespObj exportExcel(String exportBean) {
        System.out.println("exportExcel");
        System.out.println(BEAN_MAP);
        //多态
        IExportService exportService = BEAN_MAP.get(exportBean);
        Class<BaseQuery> paramClass = exportService.paramClass();
        System.out.println(paramClass);
        BaseQuery request = new BaseQuery();
        request.setPageIndex(1);
        request.setPageSize(20);
        return this.export(request,exportBean,paramClass);
    }

    private RespObj export(BaseQuery request, String exportBean, Class<BaseQuery> paramClass) {
        //往导出记录表中添加数据
        //导出状态：0导出中，1导出成功，-1导出失败，2已下载
        try {
            IExportService exportService = BEAN_MAP.get(exportBean);

            DataExport dataExport = new DataExport();
            dataExport.setTitle(exportService.title());
            dataExport.setCreateTime(System.currentTimeMillis());
            dataExport.setStatus(0);
            dataExport.setRequestClass(paramClass.getName());
            dataExportMapper.add(dataExport);

            //同步
            /**
            try {
                String link = exportService.makefile(request);
                System.out.println(link);
            }catch (Exception e){

            }
             */

            //异步进行导出操作并更新导出结果
            CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
                String link = exportService.makefile(request);
                return link;
            }, EXECUTOR_SERVICE);

            //任务完成后，执行最后的任务，并且可以获取最后任务之前的结果值
            future.whenComplete((link,t)->{
                if (t == null){
                    dataExport.setStatus(1);
                    dataExport.setDownloadLink(link);
                }
                System.out.println(t);
                System.out.println("任务结果值 "+link);

                dataExportMapper.update(dataExport);
            });

            return RespObj.build(200,"请至我的数据下载",null);
        }catch (Exception e){
            return RespObj.build(500,"导出失败",null);
        }
    }

    /**
     * 初始化Spring容器bean
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("setApplicationContext");
        this.applicationContext = applicationContext;
    }

    /**
     * 获取所有实现了IExportService接口的实现类
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet");
        BEAN_MAP = applicationContext.getBeansOfType(IExportService.class);
    }
}
